#pragma once
#include "Socket.hpp"
#include "log.hpp"
#include <vector>
#include <string>
#include <sstream>
#include <fstream>
#include <unordered_map>

using namespace std;

const string seq = "\r\n";
const string wwwroot = "./www.root";
const string homepage = "index.html";

class HttpServer;

class ThreadData
{
public:
    ThreadData(int sock, HttpServer *srv)
        : sockfd_(sock), srv_(srv)
    {
    }

    int sockfd_;
    HttpServer *srv_;
};

class HttpRequest
{
public:
    void Deserialize(string req)
    {
        while (true)
        {
            int pos = req.find(seq);
            if (pos == string::npos)
                break;

            string temp = req.substr(0, pos);
            if (temp.empty())
                break; // 说明已经走到 空行了
            req.erase(0, pos + 2);

            req_header.push_back(temp);
        }

        text = req; // 剩下的文本内容
    }

    void Parse()
    {
        stringstream ss(req_header[0]);

        ss >> method >> url >> http_version;
        file_path = wwwroot;

        if (url == "/" || url == "/index.html")
        {
            file_path += "/index.html";
        }
        else
            file_path += url;

        int pos = file_path.rfind(".");
        if (pos == string::npos)
        {
            suffix = ".html"; // 这个一会找不到可以报404；
        }
        else
            suffix = file_path.substr(pos);
    }

    void Print()
    {
        for (string &line : req_header)
        {
            cout << "------------------------" << endl;
            cout << line << "\n\n";
        }

        std::cout << "method: " << method << std::endl;
        std::cout << "url: " << url << std::endl;
        std::cout << "http_version: " << http_version << std::endl;
        std::cout << "file_path: " << file_path << std::endl;
        std::cout << text << std::endl;
    }

    vector<string> req_header;
    string text; // 中文

    string method;
    string url; // 搜索路径
    string http_version;
    string file_path;

    string suffix;
};

string ReadHtmlContent(string &htmlpath)
{
    // ifstream in(htmlpath.c_str());
    // if(!in.is_open()) return "";  //并没有这个文件

    // string ret;
    // string line;
    // while(getline(in,line))
    // {
    //     ret+=line;
    // }

    ifstream in(htmlpath, ios::binary);
    if (!in.is_open())
        return " ";

    in.seekg(0, ios_base::end);
    auto len = in.tellg();
    in.seekg(0, ios_base::beg);

    string ret;
    ret.resize(len);

    in.read((char *)ret.c_str(), ret.size());

    in.close();
    return ret;
}

class HttpServer
{
public:
    HttpServer(uint16_t port)
        : port_(port)
    {
        content_type.insert({".html", "text/html"});
        content_type.insert({".png", "image/png"});
    }

    void Start()
    {
        listensock_.Socket();
        listensock_.Bind(port_);
        listensock_.Listen();

        lg("info", "sock success");

        for (;;)
        {
            string clientip;
            uint16_t clientport;
            int sockfd_ = listensock_.Accpect(&clientip, &clientport);

            lg("info", "recv success");

            if (sockfd_ < 0)
                continue;

            pthread_t tid;
            ThreadData *d = new ThreadData(sockfd_, this);
            pthread_create(&tid, nullptr, Threadrun, d);
        }
    }

    string SuffixTo(string &suffix)
    {
        auto iter = content_type.find(suffix);
        if (iter == content_type.end())
            return content_type[".html"];

        return content_type[suffix];
    }

    void HandlerHttp(int sock)
    {
        char buffer[10240];
        ssize_t n = recv(sock, buffer, 1024, 0);
        if (n > 0)
        {
            buffer[n] = 0;
            HttpRequest req;
            req.Deserialize(buffer);
            req.Parse();
            req.Print();

            // string respone="<p>详细信息显示</p>";
            bool ok = true;
            string text = ReadHtmlContent(req.file_path);
            // if (text.empty())
            // {
            //     ok = false;
            //     req.file_path = wwwroot;
            //     req.file_path += "/";
            //     req.file_path += "Err.html";
            //     text = ReadHtmlContent(req.file_path);
            // }

            string respone_line;
            if (!ok)
            {
                respone_line = "HTTP/1.0 200 OK\r\n";
            }
            else
                respone_line = "HTTP/1.0 404 Not Found\r\n";

            if (req.file_path == "./www.root/www.qq.com")
                respone_line = "HTTP/1.0 302 Found\r\n";

            string respone_header = "Content-Length: ";
            respone_header += to_string(text.size());
            respone_header += "\r\n";

            respone_header += "Content-Type: ";
            respone_header += SuffixTo(req.suffix);
            respone_header += seq;


            if (req.file_path == "./www.root/www.qq.com")  //跳转
                respone_header += "Location: https://www.qq.com\r\n";

            respone_header += "Set-Cookie: name=hahah&&passwd=123456";
            respone_header += seq;

            string respone = respone_line;
            respone += respone_header;
            respone += "\r\n";

            respone += text;

            send(sock, respone.c_str(), respone.size(), 0);
        }

        lg("info ", "cancel link");
        close(sock);
    }

    static void *Threadrun(void *argc)
    {
        pthread_detach(pthread_self());
        ThreadData *d = static_cast<ThreadData *>(argc);
        d->srv_->HandlerHttp(d->sockfd_);
        delete d;
        return nullptr;
    }

private:
    uint16_t port_;
    Sock listensock_;

    unordered_map<string, string> content_type;
};